/*
 * Copyright (c) 2014.
 * 游戏服务器核心代码编写人陈磊拥有使用权
 * 联系方式：E-mail:13638363871@163.com ;qq:502959937
 * 个人博客主页：http://my.oschina.net/chenleijava
 */

package nettyProxyEngine4;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.apache.log4j.xml.DOMConfigurator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.util.Locale;

/**
 * @author 石头哥哥 </br>
 *         dcServer1.7 </br>
 *         Date:14-2-24 </br>
 *         Time:下午3:55 </br>
 *         Package:{@link nettyProxyEngine4}</br>
 *         Comment：代理 服务器
 */
public class ProxyServer {

    private static final Logger LOGGER= LoggerFactory.getLogger(ProxyServer.class);
    private final int localPort;     //代理服务器端口
    private final String remoteHost;     //远程ip地址
    private final int remotePort;       //远程服务器端口


    /**
     * 代理服务器
     * @param localPort
     * @param remoteHost
     * @param remotePort
     */
    public ProxyServer(int localPort, String remoteHost, int remotePort) {
        this.localPort = localPort;
        this.remoteHost = remoteHost;
        this.remotePort = remotePort;
    }

    /**
     *  java nio
     * @throws Exception
     */
    public void runProxy() throws Exception {
        // Configure the bootstrap.
        NioEventLoopGroup BossEventLoopGroup=new NioEventLoopGroup(0x1,new PriorityThreadFactory("@+监听连接线程",Thread.NORM_PRIORITY)); //mainReactor    1个线程
        NioEventLoopGroup WorkerEventLoopGroup=new NioEventLoopGroup(Runtime.getRuntime().availableProcessors()+ 0x1,new PriorityThreadFactory("@+I/O线程",Thread.NORM_PRIORITY));   //subReactor       线程数量等价于cpu个数+1
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(BossEventLoopGroup, WorkerEventLoopGroup)
                    .channel(NioServerSocketChannel.class)
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childOption(ChannelOption.SO_REUSEADDR, true)     //重用地址
                    .childOption(ChannelOption.ALLOCATOR, new PooledByteBufAllocator(false))// heap buf 's better
                    .childOption(ChannelOption.SO_RCVBUF, 1048576)
                    .childOption(ChannelOption.SO_SNDBUF, 1048576)
                    .childHandler(new ProxyServerChannelInitializer(remoteHost, remotePort))  ;
                ChannelFuture channelFuture = serverBootstrap.bind(new InetSocketAddress(localPort)).sync();
                LOGGER.debug("proxy server监听端口:"+ localPort);
               channelFuture.channel().closeFuture().sync();
        } finally {
            BossEventLoopGroup.shutdownGracefully();
            WorkerEventLoopGroup.shutdownGracefully();
        }
    }


    /**
     * jni 基于linux epoll
     * @throws Exception
     */
    public void runEpollProxy() throws Exception {
        // Configure the bootstrap.
        EpollEventLoopGroup BossEventLoopGroup=new EpollEventLoopGroup(0x1,new PriorityThreadFactory("@+监听连接线程",Thread.NORM_PRIORITY)); //mainReactor    1个线程
        EpollEventLoopGroup WorkerEventLoopGroup=new EpollEventLoopGroup(Runtime.getRuntime().availableProcessors()+ 0x1,new PriorityThreadFactory("@+I/O线程",Thread.NORM_PRIORITY));   //subReactor       线程数量等价于cpu个数+1
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(BossEventLoopGroup, WorkerEventLoopGroup)
                    .channel(NioServerSocketChannel.class)
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childOption(ChannelOption.SO_REUSEADDR, true)     //重用地址
                    .childOption(ChannelOption.ALLOCATOR, new PooledByteBufAllocator(false))// heap buf 's better
                    .childOption(ChannelOption.SO_RCVBUF, 1048576)
                    .childOption(ChannelOption.SO_SNDBUF, 1048576)
                    .childHandler(new ProxyServerChannelInitializer(remoteHost, remotePort))  ;
            ChannelFuture channelFuture = serverBootstrap.bind(new InetSocketAddress(localPort)).sync();
            LOGGER.debug("proxy server监听端口:"+ localPort);
            channelFuture.channel().closeFuture().sync();
        } finally {
            BossEventLoopGroup.shutdownGracefully();
            WorkerEventLoopGroup.shutdownGracefully();
        }
    }



    public static void main(String[] args) throws Exception {
        DOMConfigurator.configure(proxyServerConfig.DEFAULT_VALUE.FILE_PATH.LOG4J);
        proxyServerConfig.IntiProxyConfig();
        ProxyServer proxyServer= new ProxyServer(proxyServerConfig.DEFAULT_VALUE.SERVER_VALUE.proxyServerPort
                , proxyServerConfig.DEFAULT_VALUE.SERVER_VALUE.remoteHost
                , proxyServerConfig.DEFAULT_VALUE.SERVER_VALUE.remotePort);
        String name = System.getProperty("os.name").toLowerCase(Locale.UK).trim();
        if (name.startsWith("linux")) {
            proxyServer.runEpollProxy();
        } else {
            proxyServer.runProxy();
        }
    }
}
